/*****************************************************************************
	SNEGA UTILITIES 0.7a
	Copyright (C) 2009, Xiaohan Tian (snega0223)
	
	http://code.google.com/p/snega-utilities/
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License(LGPL) as
	published by the Free Software Foundation, either version 3 of the 
	License, or(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

package org.sng.util.web.elmt;

import java.util.*;

import org.sng.util.slog.*;
import org.sng.util.var.*;

public class Node {
	
	protected int m_currLineNumber;
	
	private HashMap<String, Node> idMap;
	protected HashMap<String, LinkedList<Node>> typeMap;
	
	public Node SetIdMap(HashMap<String, Node> o)
	{
		this.idMap = o;
		
		return this;
	}
	
	public Node SetTypeMap(HashMap<String, LinkedList<Node>> o)
	{
		this.typeMap = o;
		
		return this;
	}
	
	public Node AddNodeToIdMap(RuntimeEnvironment re, Node o)
	{
		SVoid id = null;
		
		if ((id = o.GetProperty("id")) != null)
		{
			this.idMap.put(id.GetString(re), o);
		}
		
		return this;
	}
	
	public Node AddNodeToIdMap(String id, Node o)
	{
		this.idMap.put(id, o);
		
		return this;
	}
	
	public Node RemoveNodeFromIdMap(String id)
	{
		this.idMap.remove(id);
		
		return this;
	}
	
	public Node AddNodeToTypeList(RuntimeEnvironment re, Node o)
	{		
		if (o.GetProperty("id") == null)
		{
			return this;
		}
		
		String type = o.GetType().toLowerCase();
		
		LinkedList<Node> ll = this.typeMap.get(type);
		
		if (ll == null)
		{
			ll = new LinkedList<Node>();
			this.typeMap.put(type, ll);
		}
		
		ll.add(o);
		
		return this;
	}
	
	public Node AddNodeToTypeList(String type, Node o)
	{
		LinkedList<Node> ll = this.typeMap.get(type);
		
		if (ll == null)
		{
			ll = new LinkedList<Node>();
			this.typeMap.put(type, ll);
		}
		
		ll.add(o);
		
		return this;
	}
	
	public Node RemoveNodeFromTypeList(String type, Node o)
	{
		LinkedList<Node> ll = this.typeMap.get(type);
		
		if (ll == null)
		{
			return this;
		}
		
		ll.remove(o);
		
		return this;
	}
	
	public Node GetNodeById(String s)
	{
		return this.idMap.get(s);
	}
	
	public LinkedList<Node> GetNodeByType(String s)
	{
		return this.typeMap.get(s);
	}
	
	public Node [] GetNodeArrayByType(String s)
	{
		LinkedList<Node> ll = this.typeMap.get(s);
		
		if (ll == null)
		{
			return null;
		}
		
		Node [] o = new Node[ll.size()]; 
		
		return ll.toArray(o);
	}

	public Node()
	{
		this.m_currLineNumber = 0;
		this.m_children = new LinkedList<Node>();
		this.m_properties = new HashMap<String, SVoid>();
		
		this.idMap = new HashMap<String, Node>();
		this.typeMap = new HashMap<String, LinkedList<Node>>();
	}
	
	public Node(int n)
	{
		this.m_currLineNumber = n;
		this.m_children = new LinkedList<Node>();
		this.m_properties = new HashMap<String, SVoid>();
		
		this.idMap = new HashMap<String, Node>();
		this.typeMap = new HashMap<String, LinkedList<Node>>();
	}
	
	public Node Create()
	{
		return new Node();
	}
	
	public Node Create(int n)
	{
		return new Node(n);
	}
	
	public Node Create(String id, RuntimeEnvironment re)
	{
		Node o = new Node();
		
		o.m_properties.put("id", new SString(id));
		
		return o;
	}
	
	public String GetType()
	{
		return "node";
	}
	
	protected HashMap<String, SVoid> m_properties;
	
	public Node PushProperty(String header, String s)
	{
		return this.PushProperty(header, new SString(s));
	}
	
	public Node PushProperty(String header, int n)
	{
		return this.PushProperty(header, new SInt(n));
	}
	
	public Node PushProperty(String header, SVoid o)
	{
		this.m_properties.put(header, o);
		
		return this;
	}
	
	public Node RemoveProperty(String header)
	{
		this.m_properties.remove(header);
		
		return this;
	}
	
	public SVoid GetProperty(String header)
	{
		return this.m_properties.get(header);
	}
	
	protected LinkedList<Node> m_children;
	
	public Node AddChild(Node o)
	{
		this.m_children.add(o);
		
		this.AddNodeToTypeList(o.GetType(), o);
		
		return this;
	}
	
	public Node AddChild(RuntimeEnvironment re, Node o)
	{
		this.m_children.add(o);
		
		re.GetRoot().AddNodeToIdMap(re, o);
		re.GetRoot().AddNodeToTypeList(re, o);
		
		this.AddNodeToTypeList(o.GetType(), o);
		
		return this;
	}
	
	public Node [] GetChildren()
	{
		Node [] children = new Node[this.m_children.size()];
		
		return this.m_children.toArray(children);
	}
	
	public StringBuffer Execute(RuntimeEnvironment re)
	{
		StringBuffer result = new StringBuffer();
		
		try {
			result.append(this.Do(re));
			
			this.AppendPostList(re);
			
			ListIterator<Node> interator = this.m_children.listIterator();
			
	        while (interator.hasNext())
	        {
	        	result.append(interator.next().Execute(re));
	        }
		} catch (Exception e) {
			SLog.println("Webpage runtime error on line " + this.m_currLineNumber);
			e.printStackTrace();
		}
		
		return result;
	}
	
	public StringBuffer Do(RuntimeEnvironment re) throws Exception
	{
		return new StringBuffer();
	}
	
	public void AppendPostList(RuntimeEnvironment re)
	{
		
	}
	
	public Node ClearChildren(RuntimeEnvironment re)
	{
		return this;
	}
	
	public Node AppendChild(RuntimeEnvironment re, Node o)
	{
		return this;
	}

}
